﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Ddavidlib.GameEngine.SLGMap
{
    // A Map must be able to do these things:
    // 1. calculates the distance and/or the movement required from a Position to another Position
    // 2. shows that if two Positions are adjacent
    // 3. gives a reachable Position list by given movement
    // 4. finds out the shortest path between two Positions
    interface IMap<TPosition, TDistance, TMovement, TMovingStyle>
    {
        TDistance GetDestance(TPosition posA, TPosition posB);
        bool IsAdjacent(TPosition posA, TPosition posB);
        List<TPosition> GetReachablePositions(TPosition pos, TMovingStyle moveStyle, TMovement movement);
        List<TPosition> GetPath(TPosition posA, TPosition posB, TMovingStyle moveStyle);
    }

    public class Position2D
    {
        public int x { get; set; }
        public int y { get; set; }

        public Position2D()
            : this(0, 0)
        {
        }

        public Position2D(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public override string ToString()
        {
            return "(" + x.ToString() + ", " + y.ToString() + ")";
        }
    }

    public class Distance2D
    {
        public int distance { set; get; }

        public Distance2D()
        {
            distance = 0;
        }

        public Distance2D(int distance)
        {
            this.distance = distance;
        }

        public override string ToString()
        {
            return distance.ToString();
        }
    }

    public class Movement2D
    {
        public int movement { set; get; }

        public Movement2D()
        {
            movement = 0;
        }

        public Movement2D(int movement)
        {
            this.movement = movement;
        }

        public override string ToString()
        {
            return movement.ToString();
        }
    }

    public class MovingStyle2D
    {
        public enum MovingStyleTable
        {
            kNormal,
        }

        public MovingStyleTable movingStyle { set; get; }

        public MovingStyle2D()
        {
            movingStyle = MovingStyleTable.kNormal;
        }

        public MovingStyle2D(MovingStyleTable movingStyle)
        {
            this.movingStyle = movingStyle;
        }

        public override string ToString()
        {
            return movingStyle.ToString();
        }
    }

    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Map2D : LogGameComponent, IMap<Position2D, Distance2D, Movement2D, MovingStyle2D>
    {
        public Map2D(Game game, string name, LogSystem usedLogSystem)
            : base(game, name, usedLogSystem)
        {
            // TODO: Construct any child components here
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            base.Update(gameTime);
        }

        public Distance2D GetDestance(Position2D posA, Position2D posB)
        {
            Distance2D distance = new Distance2D(Math.Abs(posA.x - posB.x) + Math.Abs(posA.y - posB.y));

            return distance;
        }

        public bool IsAdjacent(Position2D posA, Position2D posB)
        {
            if (Math.Abs(posA.x - posB.x) + Math.Abs(posA.y - posB.y) == 1)
            {
                return true;
            }
            return false;
        }

        public List<Position2D> GetReachablePositions(Position2D pos, MovingStyle2D moveStyle, Movement2D movement)
        {
        }

        public List<Position2D> GetPath(Position2D posA, Position2D posB, MovingStyle2D moveStyle)
        {
        }
    }
}
